import requests
import numpy as np
from PIL import Image
from io import BytesIO
import json

# 全局变量用于手动修改 IP 和端口
CAM_SERVER_URL = 'http://192.168.31.79:5000'
SERIAL_SERVER_URL = 'http://192.168.31.79:5001'

def get_image_as_tensor():
    """
    从摄像头服务器获取一张图像并将其转换为 NumPy 张量。

    :return: NumPy 张量表示的图像
    :raises Exception: 如果获取图像失败
    """
    response = requests.get(f'{CAM_SERVER_URL}/capture')
    if response.status_code == 200:
        image = Image.open(BytesIO(response.content))
        return np.array(image)
    else:
        raise Exception(f"Failed to get image, status code: {response.status_code}")

def get_available_cameras():
    """
    获取摄像头服务器上可用的摄像头列表。

    :return: 可用摄像头列表
    :raises Exception: 如果获取摄像头列表失败
    """
    response = requests.get(f'{CAM_SERVER_URL}/scan_cameras')
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"Failed to get cameras, status code: {response.status_code}")

def set_camera(camera_index):
    """
    设置当前使用的摄像头。

    :param camera_index: 摄像头索引
    :return: 设置结果
    :raises Exception: 如果设置摄像头失败
    """
    response = requests.post(f'{CAM_SERVER_URL}/set_camera/{camera_index}')
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"Failed to set camera, status code: {response.status_code}")

def get_camera_details(camera_index:int=None):
    """
    获取指定摄像头的详细信息。

    :param camera_index: 摄像头索引
    :return: 摄像头详细信息
    :raises Exception: 如果获取摄像头详情失败
    """
    if camera_index is None:
        camera_index = 0
    response = requests.get(f'{CAM_SERVER_URL}/camera_details/{camera_index}')
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"Failed to get camera details, status code: {response.status_code}")

def get_video_feed():
    """
    获取当前摄像头的实时视频流。

    :return: 实时视频流的内容迭代器
    :raises Exception: 如果获取视频流失败
    """
    response = requests.get(f'{CAM_SERVER_URL}/video_feed', stream=True)
    if response.status_code == 200:
        return response.iter_content(chunk_size=1024)
    else:
        raise Exception(f"Failed to get video feed, status code: {response.status_code}")

def close_camera():
    """
    关闭当前摄像头。

    :return: 关闭结果
    :raises Exception: 如果关闭摄像头失败
    """
    response = requests.post(f'{CAM_SERVER_URL}/close_camera')
    if response.status_code == 200:
        return dict(response.json())
    else:
        raise Exception(f"Failed to close camera, status code: {response.status_code}")

def scan_serial_ports():
    """
    扫描本机可用的串口。

    :return: 可用串口列表
    :raises Exception: 如果扫描串口失败
    """
    response = requests.get(f'{SERIAL_SERVER_URL}/scan_serial_ports')
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"Failed to scan serial ports, status code: {response.status_code}")

def open_serial_port(port, baud_rate):
    """
    打开指定的串口。

    :param port: 串口端口
    :param baud_rate: 串口波特率
    :return: 打开结果
    :raises Exception: 如果打开串口失败
    """
    response = requests.post(f'{SERIAL_SERVER_URL}/open_serial_port', json={'port': port, 'baudRate': baud_rate})
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"Failed to open serial port, status code: {response.status_code}")

def close_serial_port():
    """
    关闭当前串口。

    :return: 关闭结果
    :raises Exception: 如果关闭串口失败
    """
    response = requests.post(f'{SERIAL_SERVER_URL}/close_serial_port')
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"Failed to close serial port, status code: {response.status_code}")

def send_serial_data(data, newline_index):
    """
    发送数据到串口。

    :param data: 要发送的数据
    :param newline_index: 换行符索引
    :return: 发送结果
    :raises Exception: 如果发送数据失败
    """
    response = requests.post(f'{SERIAL_SERVER_URL}/send_data', json={'data': data, 'newline': newline_index})
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"Failed to send serial data, status code: {response.status_code}")

def read_serial_data():
    """
    从串口读取数据。

    :return: 读取的数据
    :raises Exception: 如果读取数据失败
    """
    response = requests.get(f'{SERIAL_SERVER_URL}/read_serial_data')
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"Failed to read serial data, status code: {response.status_code}")

def get_last_serial_settings():
    """
    获取上次使用的串口设置。

    :return: 上次使用的串口设置
    :raises Exception: 如果获取设置失败
    """
    response = requests.get(f'{SERIAL_SERVER_URL}/get_last_settings')
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"Failed to get last serial settings, status code: {response.status_code}")

def get_serial_status():
    """
    获取串口状态。

    :return: 串口状态
    :raises Exception: 如果获取状态失败
    """
    response = requests.get(f'{SERIAL_SERVER_URL}/get_serial_status')
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"Failed to get serial status, status code: {response.status_code}")
